package com.json.smtest.SMUtils.SM2_2;

import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ECPoint;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

public class SM2Util {


    private static SM2Util instance = new SM2Util();
    private static String privateKeyHex;
    public static String  publicKeyHex;

    private SM2Util() {
    }

    public static SM2Util getInstance() throws NoSuchAlgorithmException {
        //生成密钥对
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
        ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
        keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
        AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();

//私钥，16进制格式，自己保存，格式如a2081b5b81fbea0b6b973a3ab6dbbbc65b1164488bf22d8ae2ff0b8260f64853
        BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
        String privateKeyHex = privatekey.toString(16);

//公钥，16进制格式，发给前端，格式如04813d4d97ad31bd9d18d785f337f683233099d5abed09cb397152d50ac28cc0ba43711960e811d90453db5f5a9518d660858a8d0c57e359a8bf83427760ebcbba
        ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
        String publicKeyHex = Hex.toHexString(ecPoint.getEncoded(false));


        System.out.println("privateKeyHex :"+ privateKeyHex);
        System.out.println("publicKeyHex  :"+ publicKeyHex);

        return SM2Util.instance;
    }

    /**
     * 解密SM2
     *
     * @param text 密文
     * @return 明文
     */
    public static String decrypt(String text,String privateKeyHex)  {


        //JS加密产生的密文
        byte[] cipherDataByte = Hex.decode(text);

        //刚才的私钥Hex，先还原私钥
//        String privateKey = "a2081b5b81fbea0b6b973a3ab6dbbbc65b1164488bf22d8ae2ff0b8260f64853";
        String privateKey = privateKeyHex;
        BigInteger privateKeyD = new BigInteger(privateKey, 16);
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
        ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);

        //用私钥解密
        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(false, privateKeyParameters);

        try {
            //processBlock得到Base64格式，记得解码
            byte[] arrayOfBytes = Base64.getDecoder().decode(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length));
            //得到明文：SM2 Encryption Test
            String data = new String(arrayOfBytes);
            return data;
        } catch (InvalidCipherTextException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 加密SM2
     *
     * @param text 明文
     * @return 密文
     */
    public static String encrypt(String text,String publicKeyHex) {
        byte[] plaintextByte = Base64.getEncoder().encode(text.getBytes());
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        ECDomainParameters domainParams = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
        X9ECPoint localX9ECPoint = new X9ECPoint(sm2ECParameters.getCurve(), Hex.decode(publicKeyHex.getBytes()));
        ECPublicKeyParameters pk = new ECPublicKeyParameters(localX9ECPoint.getPoint(), domainParams);
        CipherParameters pubKeyParameters = new ParametersWithRandom(pk);
        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(true, pubKeyParameters);
        try {
            return Hex.toHexString(sm2Engine.processBlock(plaintextByte, 0, plaintextByte.length));
        } catch (InvalidCipherTextException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        //getInstance();
        String publicKey="04597cea81267d1e78598714eeb117fc5748914841719e8e11945c5b7e8dc1ceb4a8a7381ea7c6c35d8c78a9f78a65582e6e0ca5267af30e6e068818ea514c1094";
        String privateKey="b09dd8057c50e6e740ad405ab51e5683842744fa402f20bc96d5e34437a8a08c";
        String text = "1234561qaz@WSX中国";
        String encrypt = encrypt(text, publicKey);
        System.out.println("sm2加密后:"+encrypt);

        String decrypt = decrypt(encrypt, privateKey);
        System.out.println("sm2解密后:"+decrypt);
    }
}
